(function(func){
    if( typeof(define) === undefined ){
        define('dynamicParse',['dynamicWrite'],function(write){
            return func(window,write) ;
        }) ;
    } else {
        window.dynamic = window.dynamic||{} ;
        window.dynamic.Parse = func(window,window.dynamic.write) ;
    }
}(function(win,write){

    var typeWrap = {
        'note' : '<p class="codeNote"></p>' ,
        'css' : '<pre class="codeCss" ></pre>' ,
        'js' : '<pre class="codeJs" ></pre>',
        getDom : function( type ){
            var domStr = this[type] || this.note ;
            var div = document.createElement('div') ;
            div.innerHTML = domStr ;
            var dom = div.childNodes[0] ;
            div.removeChild(dom) ;
            return dom ;
        }
    } ;
    var startRegex = {
        'css' : /^\s*\!/ ,
        'js' : /^\s*\~/
    } ;
    var speed = 80 ;
    var getNextFrame = function(){
            if( typeof arguments[0] === 'function' ){
                return window.setTimeout( arguments[0] , arguments[1] || speed ) ;
            }
        } ;
    var cancelNextFrame =  function(){
        return window.clearTimeout(arguments[0]) ;
    } ;

    var showAnimation = function( dom , str ,cb , timeout ){
        var index = 0 ;
        var nextFrame = function(){
            var text = document.createTextNode( str[ index++ ] ) ;
            dom.appendChild( text ) ;
            if( index === str.length ){
                if( typeof cb === 'function' ) {
                    getNextFrame( cb , timeout ) ;
                }
            }else{
                getNextFrame( nextFrame ) ;
            }
        } ;
        nextFrame();
    } ;

    var Parse = function( dom ){
        this.dom = dom ;
        this.list = [] ;
        this.isRunning = false ;
        this.index = 0 ;
        this.timeout = null ;
    } ;

    Parse.prototype.push = function(str){
        var splitChar = '\n' ;
        this.list = this.list.concat( str.split(splitChar) ) ;
        this.start() ;
    } ;
    var codeArr = [] ;
    var codeType = '' ;

    Parse.prototype.start = function(){
        if(this.isRunning){return ;}
        this.isRunning = true ;
        var self = this ;
        var run = function(){
            var  runStr = self.list[self.index++] ;
            var writeFun = function(){} ;
            var type = 'note' ;
            if( startRegex.css.test( runStr ) ){
                type = 'css' ;
            }else if( startRegex.js.test( runStr ) ){
                type = 'js' ;
            }else{
                type = 'note' ;
            }
            runStr = runStr.replace(startRegex.css,'').replace(startRegex.js,'') + '\n' ; ;
            var isNotShow = runStr[0] === '#' ;
            runStr = runStr.replace(/^\#/,'') ;
            if( codeType === type ){
                codeArr.push(runStr) ;
            } else {
                if( codeType === 'js' || codeType ==='css' ){
                    write[codeType](codeArr.join('')) ;
                }
                if( type === 'js' || type=== 'css' ){ codeArr = [runStr] ; }
            }
            codeType = type ;

            if( isNotShow ){
                if( self.index < self.list.length ){
                    run() ;
                }else if( type === 'js' || type === 'css' ){
                    write[type](codeArr.join('')) ;
                }
            }else{
                var container = typeWrap.getDom(type) ;
                self.dom.appendChild(container) ;
                showAnimation( container , runStr ,function(){
                    if( self.index < self.list.length ){
                        self.timeout = getNextFrame(run) ;
                    }else if( type === 'js' || type === 'css' ){
                        write[type](codeArr.join('')) ;
                    }
                } ) ;
            }
        } ;
        run() ;
    } ;
    Parse.prototype.setDom = function(dom){
        this.dom = dom ;
    } ;
    Parse.prototype.pause = function(){
        window.clearTimeout( this.timeout ) ;
        this.isRunning = false ;
    } ;
    return function(){
        return new Parse(arguments[0]) ;
    } ;
})) ;